﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;
using LogLib;
using System.Threading.Tasks;
using System.Diagnostics;

namespace IPCPhotoEditor.Common
{
    /// <summary>
    /// 异步任务运行状态
    /// </summary>
    public enum AsyncTaskState : int
    {    
        /// <summary>
        /// 等待执行
        /// </summary>
        Ready = 0,
        /// <summary>
        /// 正在执行
        /// </summary>
        Running = 1,
        /// <summary>
        /// 已终止
        /// </summary>
        Terminated = 2
    }

    public class QueueTaskManager : IDisposable
    {
        /// <summary>
        /// 标记任务是否已经取消
        /// </summary>
        private bool _bCancelled = false;
        public bool Cancelled
        {
            get { return _bCancelled; }
            set { _bCancelled = value; }
        }

        /// <summary>
        /// 等待处理事件
        /// </summary>
        protected ManualResetEventSlim _mresWaitHandler = new ManualResetEventSlim(false);

        /// <summary>
        /// 存储队列任务
        /// </summary>
        private ConcurrentStack<IQueueAction> _tasks = new ConcurrentStack<IQueueAction>();

        /// <summary>
        /// 用于禁止可重入操作
        /// </summary>
        private int syncPoint = 0;

        /// <summary>
        /// UI线程同步上下文，用于从工作线程向UI线程封送消息(事件或动作)
        /// </summary>
        public SynchronizationContext Context
        {
            get;
            set;
        }

        /// <summary>
        /// 任务运行状态
        /// </summary>
        protected AsyncTaskState _state = AsyncTaskState.Ready;
        public AsyncTaskState State
        {
            get
            {
                return _state;
            }
        }
        
        protected SendOrPostCallback onUpdateUIDelegate;

        protected Thread _thread = null;

        /// <summary>
        /// 工作线程的栈空间大小
        /// </summary>
        private int MaxStackSize = 0;

        /// <summary>
        /// 指示循环任务是否结束的计时器事件
        /// </summary>
        private CountdownEvent _cdeWaitingForTerminated = new CountdownEvent(1);

        /// <summary>
        /// 上一个任务的时间戳
        /// </summary>
        private long LastTaskTimestamp = 0;

        public QueueTaskManager()
        {
  
        }

        public QueueTaskManager(int stackSize)
            : this()
        {
            MaxStackSize = stackSize;
        }

        protected void SendUpdateUICommand(Action handler)
        {
            if (Context != null)
            {
                Context.Send((s) =>
                {
                    handler();
                },null);
            }
        }

        public void AddTask(IQueueAction task, bool onForced = false)
        {
            if (this._state == AsyncTaskState.Terminated)
            {
                return;
            }
            if (onForced)
            {
                _tasks.Clear();
            }
            _tasks.Push(task);
            SetEvent();
        }

        /// <summary>
        /// 在线程方法中循环执行的工作项
        /// </summary>
        /// <param name="handler"></param>
        private void OnWorkItem(IQueueAction task)
        {
            if (syncPoint == 1)
            {
                // 上一个任务未结束，中止/取消本次任务运行
                return;
            }
            int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
            if (sync != 0)
            {
                return;
            }
            try
            {
                SendUpdateUICommand(task.OnPrepared);
                task.Execute();
                SendUpdateUICommand(task.UpdateUI);
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
            finally
            {
                syncPoint = 0;
            }
        }

        public void StartWorking()
        {
            // Start the asynchronous operation.
            _thread = new Thread(Worker, MaxStackSize);
            _thread.IsBackground = true;
            _thread.Start();
        }

        /// <summary>
        /// 运行在一个线程中的循环工作
        /// </summary>
        /// <param name="asyncOp"></param>
        protected void Worker()
        {
            try
            {
                while (!Cancelled)
                {
                    LastTaskTimestamp = 0;
                    _state = AsyncTaskState.Ready;
                    _mresWaitHandler.Wait();
                    if (Cancelled)
                    {
                        break;
                    }
                    _state = AsyncTaskState.Running;
                    IQueueAction task;
                    while (!_tasks.IsEmpty && !Cancelled)
                    {
                        if (_tasks.TryPop(out task))
                        {
                            // 只执行时间发生更新的任务
                            if (task.Timestamp >= LastTaskTimestamp)
                            {
                                OnWorkItem(task);
                                LastTaskTimestamp = task.Timestamp;
                            }
                            else
                            {
                                _tasks.Clear();
                            }
                        }
                    }
                    Wait();
                }
            }
            catch (System.Exception e)
            {
                Log.WriteException(e.ToString());
            }
            finally
            {
                Dispose();
                _state = AsyncTaskState.Terminated;
                _cdeWaitingForTerminated.Signal();
            }
        }

        /// <summary>
        /// 使等待事件获得信号, 恢复被暂停/阻塞的工作项任务
        /// </summary>
        public void SetEvent()
        {
            _mresWaitHandler.Set();
        }

        /// <summary>
        /// 判断等待对象是否获得信号,
        /// </summary>
        protected bool Signalled()
        {
            if (_mresWaitHandler != null)
            {
                return _mresWaitHandler.IsSet;
            }
            return false;
        }

        /// <summary>
        /// 暂停/阻塞任务
        /// </summary>rtual 
        public void Wait()
        {
            _mresWaitHandler.Reset();
        }

        /// <summary>
        /// 等待直到后台任务准备就绪
        /// </summary>
        /// <param name="time_out">超时时间</param>
        /// <returns>超时时间之前条件得到满足，返回true; 超时返回false</returns>
        public bool WaitForReady(int time_out = 10000)
        {
            return SpinWait.SpinUntil(() => (State == AsyncTaskState.Ready), time_out);
        }

        /// <summary>
        /// 等待直到后台任务终止
        /// </summary>
        public void WaitForTerminated(int time_out = 10000)
        {         
            _cdeWaitingForTerminated.Wait(time_out);          
        }

        public void Dispose()
        {

        }

        public void Stop(int time_out)
        {
            _bCancelled = true;
            SetEvent();
            WaitForTerminated(time_out);
        }
    }
}
